ããã³ããšã³ãã®RTCPeerConnectionããŒã«ãããŒãžã£ãŒãå®è£ ããWebRTCã¢ããªã±ãŒã·ã§ã³ã®é å»¶ãšãªãœãŒã¹äœ¿çšéãå€§å¹ ã«åæžããæ¹æ³ãåŠã³ãŸãããšã³ãžãã¢åãã®å æ¬çãªã¬ã€ãã
WebRTCããã³ããšã³ãæ¥ç¶ããŒã«ãããŒãžã£ãŒïŒãã¢æ¥ç¶æé©åã®åŸ¹åºè§£èª¬
çŸä»£ã®ãŠã§ãéçºã«ãããŠããªã¢ã«ã¿ã€ã éä¿¡ã¯ãã¯ãããããªæ©èœã§ã¯ãªãããŠãŒã¶ãŒãšã³ã²ãŒãžã¡ã³ãã®èŠãšãªã£ãŠããŸããã°ããŒãã«ãªãããªäŒè°ãã©ãããã©ãŒã ãã€ã³ã¿ã©ã¯ãã£ããªã©ã€ãã¹ããªãŒãã³ã°ãããå ±åäœæ¥ããŒã«ããªã³ã©ã€ã³ã²ãŒã ã«è³ããŸã§ãç¬æã§äœé å»¶ãªã€ã³ã¿ã©ã¯ã·ã§ã³ãžã®éèŠã¯é«ãŸãäžæ¹ã§ãããã®å€é©ã®äžå¿ã«ããã®ãWebRTCïŒWeb Real-Time CommunicationïŒã§ããããã©ãŠã¶å ã§çŽæ¥ãã¢ããŒãã¢éä¿¡ãå¯èœã«ãã匷åãªãã¬ãŒã ã¯ãŒã¯ã§ãããããããã®åãå¹ççã«æŽ»çšããã«ã¯ãç¹ã«ããã©ãŒãã³ã¹ãšãªãœãŒã¹ç®¡çã«é¢ããŠãåºæã®èª²é¡ã䌎ããŸããæãéèŠãªããã«ããã¯ã®1ã€ã¯ãWebRTCã»ãã·ã§ã³ã®åºæ¬çãªæ§æèŠçŽ ã§ããRTCPeerConnectionãªããžã§ã¯ãã®äœæãšèšå®ã§ãã
æ°ãããã¢ããŒãã¢ãªã³ã¯ãå¿ èŠã«ãªããã³ã«ãæ°ããRTCPeerConnectionãã€ã³ã¹ã¿ã³ã¹åãããèšå®ãããããŽã·ãšãŒããããå¿ èŠããããŸããSDPïŒSession Description ProtocolïŒäº€æãšICEïŒInteractive Connectivity EstablishmentïŒåè£åéãå«ããã®ããã»ã¹ã¯ãé¡èãªé å»¶ãåŒãèµ·ãããããªãã®CPUããã³ã¡ã¢ãªãªãœãŒã¹ãæ¶è²»ããŸããé »ç¹ãŸãã¯å€æ°ã®æ¥ç¶ã䌎ãã¢ããªã±ãŒã·ã§ã³âãã¬ã€ã¯ã¢ãŠãã«ãŒã ã«çŽ æ©ãåå ãããéåºããããããŠãŒã¶ãŒãåçãªã¡ãã·ã¥ãããã¯ãŒã¯ããŸãã¯ã¡ã¿ããŒã¹ç°å¢ãèããŠã¿ãŠãã ããâãã®ãªãŒããŒãããã¯ãåŠçã®é ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæ¥ç¶æéã®é å»¶ãã¹ã±ãŒã©ããªãã£ã®æªå€¢ã«ã€ãªããå¯èœæ§ããããŸããããã§æŠç¥çãªã¢ãŒããã¯ãã£ãã¿ãŒã³ã圹ç«ã¡ãŸã: WebRTCããã³ããšã³ãæ¥ç¶ããŒã«ãããŒãžã£ãŒã§ãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãããŒã¿ããŒã¹æ¥ç¶ã«äŒçµ±çã«äœ¿çšãããŠãããã¶ã€ã³ãã¿ãŒã³ã§ããã³ãã¯ã·ã§ã³ããŒã«ãããŒãžã£ãŒã®æŠå¿µãæ¢æ±ãããããããã³ããšã³ãWebRTCã®ãŠããŒã¯ãªäžçã«é©å¿ãããŸããåé¡ç¹ãåæããå ç¢ãªãœãªã¥ãŒã·ã§ã³ãèšèšããå®çšçãªå®è£ ã®æŽå¯ãæäŸããã°ããŒãã«ãªãŒãã£ãšã³ã¹åãã®é«æ§èœãã¹ã±ãŒã©ãã«ãå¿çæ§ã®é«ããªã¢ã«ã¿ã€ã ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®é«åºŠãªèæ ®äºé ã«ã€ããŠè°è«ããŸãã
ã³ã¢åé¡ã®çè§£ïŒRTCPeerConnectionã®ã³ã¹ãã®ãããã©ã€ããµã€ã¯ã«
ãœãªã¥ãŒã·ã§ã³ãæ§ç¯ããåã«ãåé¡ãå®å šã«ææ¡ããå¿ èŠããããŸããRTCPeerConnectionã¯è»œéãªãªããžã§ã¯ãã§ã¯ãããŸããããã®ã©ã€ããµã€ã¯ã«ã«ã¯ããã¢éã§ã¡ãã£ã¢ãæµããåã«å®äºããå¿ èŠããããããã€ãã®è€éã§éåæãã€ãªãœãŒã¹ã倧éã«æ¶è²»ããã¹ããããå«ãŸããŸãã
å žåçãªæ¥ç¶ã®éã®ã
åäžã®ãã¢æ¥ç¶ã確ç«ããã«ã¯ãé垞以äžã®ã¹ããããèžã¿ãŸã:
- ã€ã³ã¹ã¿ã³ã¹å: new RTCPeerConnection(configuration)ã§æ°ãããªããžã§ã¯ããäœæãããŸããèšå®ã«ã¯ãNATãã©ããŒãµã«ã®ããã«å¿ èŠãªSTUN/TURNãµãŒããŒïŒiceServersïŒã®ãããªéèŠãªè©³çްãå«ãŸããŸãã
- ãã©ãã¯ã®è¿œå : addTrack()ã䜿çšããŠã¡ãã£ã¢ã¹ããªãŒã ïŒãªãŒãã£ãªããããªïŒãæ¥ç¶ã«è¿œå ãããŸããããã«ãããæ¥ç¶ã¯ã¡ãã£ã¢ãéä¿¡ããæºåãã§ããŸãã
- ãªãã¡ãŒã®äœæ: äžæ¹ã®ãã¢ïŒçºä¿¡è ïŒã¯createOffer()ã§SDPãªãã¡ãŒãäœæããŸãããã®ãªãã¡ãŒã¯ãçºä¿¡è ã®èгç¹ããã®ã¡ãã£ã¢æ©èœãšã»ãã·ã§ã³ãã©ã¡ãŒã¿ãèšè¿°ããŸãã
- ããŒã«ã«èšè¿°ã®èšå®: çºä¿¡è ã¯setLocalDescription()ã䜿çšããŠããã®ãªãã¡ãŒãèªèº«ã®ããŒã«ã«èšè¿°ãšããŠèšå®ããŸãããã®ã¢ã¯ã·ã§ã³ã¯ICEã®ã£ã¶ãªã³ã°ããã»ã¹ãããªã¬ãŒããŸãã
- ã·ã°ããªã³ã°: ãªãã¡ãŒã¯ãå¥ã®ã·ã°ããªã³ã°ãã£ãã«ïŒäŸïŒWebSocketsïŒãä»ããŠçžæã®ãã¢ïŒçä¿¡è ïŒã«éä¿¡ãããŸããããã¯ãæ§ç¯ããå¿ èŠããã垯åå€éä¿¡ã¬ã€ã€ãŒã§ãã
- ãªã¢ãŒãèšè¿°ã®èšå®: çä¿¡è ã¯ãªãã¡ãŒãåãåããsetRemoteDescription()ã䜿çšããŠããããèªèº«ã®ãªã¢ãŒãèšè¿°ãšããŠèšå®ããŸãã
- ã¢ã³ãµãŒã®äœæ: çä¿¡è ã¯createAnswer()ã§SDPã¢ã³ãµãŒãäœæãããªãã¡ãŒã«å¿çããŠèªèº«ã®æ©èœã®è©³çްãèšè¿°ããŸãã
- ããŒã«ã«èšè¿°ã®èšå®ïŒçä¿¡è ïŒ: çä¿¡è ã¯ãã®ã¢ã³ãµãŒãèªèº«ã®ããŒã«ã«èšè¿°ãšããŠèšå®ããèªèº«ã®ICEã®ã£ã¶ãªã³ã°ããã»ã¹ãããªã¬ãŒããŸãã
- ã·ã°ããªã³ã°ïŒè¿ä¿¡ïŒ: ã¢ã³ãµãŒã¯ã·ã°ããªã³ã°ãã£ãã«ãä»ããŠçºä¿¡è ã«éãè¿ãããŸãã
- ãªã¢ãŒãèšè¿°ã®èšå®ïŒçºä¿¡è ïŒ: å ã®çºä¿¡è ã¯ã¢ã³ãµãŒãåãåãããããèªèº«ã®ãªã¢ãŒãèšè¿°ãšããŠèšå®ããŸãã
- ICEåè£ã®äº€æ: ãã®ããã»ã¹å šäœãéããŠãäž¡æ¹ã®ãã¢ã¯ICEåè£ïŒæœåšçãªãããã¯ãŒã¯ãã¹ïŒãåéããã·ã°ããªã³ã°ãã£ãã«ãä»ããŠäº€æããŸãã圌ãã¯ãããã®ãã¹ããã¹ãããŠãåäœããã«ãŒããèŠã€ããŸãã
- æ¥ç¶ã®ç¢ºç«: é©åãªåè£ãã¢ãèŠã€ãããDTLSãã³ãã·ã§ã€ã¯ãå®äºãããšãæ¥ç¶ç¶æ ã¯'connected'ã«å€åããã¡ãã£ã¢ã®ãããŒãéå§ãããŸãã
æããã«ãªãããã©ãŒãã³ã¹ã®ããã«ããã¯
ãã®éã®ããåæãããšãããã€ãã®éèŠãªããã©ãŒãã³ã¹äžã®åé¡ç¹ãæããã«ãªããŸã:
- ãããã¯ãŒã¯é å»¶: ãªãã¡ãŒ/ã¢ã³ãµãŒã®äº€æãšICEåè£ã®ããŽã·ãšãŒã·ã§ã³å šäœã«ã¯ãã·ã°ããªã³ã°ãµãŒããŒãä»ããè€æ°åã®ã©ãŠã³ãããªãããå¿ èŠã§ãããã®ããŽã·ãšãŒã·ã§ã³æéã¯ããããã¯ãŒã¯ç¶æ³ããµãŒããŒã®å Žæã«ãã£ãŠãç°¡åã«500ããªç§ããæ°ç§ã«åã¶ããšããããŸãããŠãŒã¶ãŒã«ãšã£ãŠã¯ãããã¯ç¡é§ãªæéã§ãããé話ãéå§ãããããããªã衚瀺ããããŸã§ã«é¡èãªé å»¶ãçºçããŸãã
- CPUãšã¡ã¢ãªã®ãªãŒããŒããã: æ¥ç¶ãªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹åãSDPã®åŠçãICEåè£ã®åéïŒãããã¯ãŒã¯ã€ã³ã¿ãŒãã§ãŒã¹ãSTUN/TURNãµãŒããŒãžã®åãåããã䌎ãããšããããŸãïŒãDTLSãã³ãã·ã§ã€ã¯ã®å®è¡ã¯ãã¹ãŠèšç®è² è·ãé«ãã§ããããã倿°ã®æ¥ç¶ã«å¯ŸããŠç¹°ãè¿ãè¡ããšãCPUã¹ãã€ã¯ãåŒãèµ·ãããã¡ã¢ãªãããããªã³ããå¢å ãããã¢ãã€ã«ããã€ã¹ã®ããããªãŒãæ¶èãããå¯èœæ§ããããŸãã
- ã¹ã±ãŒã©ããªãã£ã®åé¡: åçãªæ¥ç¶ãå¿ èŠãšããã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã®èšå®ã³ã¹ãã®çޝç©å¹æã¯å£æ» çã§ããæ°ããåå è ã®åå ãé ãããã«ãããŒãã£ãããªéè©±ãæ³åããŠã¿ãŠãã ããããã®åå è ã®ãã©ãŠã¶ã¯ãä»ã®ãã¹ãŠã®åå è ãšé çªã«æ¥ç¶ã確ç«ããå¿ èŠãããããã§ãããããã¯ãæ°ãã人ã ã®ã°ã«ãŒãã«ç§»åãããšãæ¥ç¶èšå®ã®åµãããªã¬ãŒããããœãŒã·ã£ã«VR空éãæ³åããŠã¿ãŠãã ããããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã¯ãã·ãŒã ã¬ã¹ãªãã®ããããã¡ãªããã®ãžãšããã«å£åããŸãã
解決çïŒããã³ããšã³ãæ¥ç¶ããŒã«ãããŒãžã£ãŒ
ã³ãã¯ã·ã§ã³ããŒã«ã¯ãããã«äœ¿çšã§ãããªããžã§ã¯ãã€ã³ã¹ã¿ã³ã¹ã®ãã£ãã·ã¥ãç¶æããå€å žçãªãœãããŠã§ã¢ãã¶ã€ã³ãã¿ãŒã³ã§ãããã®å Žåãããã¯RTCPeerConnectionãªããžã§ã¯ãã§ããæ¥ç¶ãå¿ èŠã«ãªããã³ã«ãŒãããæ°ããæ¥ç¶ãäœæãã代ããã«ãã¢ããªã±ãŒã·ã§ã³ã¯ããŒã«ããæ¥ç¶ãèŠæ±ããŸããã¢ã€ãã«ç¶æ ã§äºåã«åæåãããæ¥ç¶ãå©çšå¯èœãªå Žåãæãæéã®ãããèšå®ã¹ãããããã€ãã¹ããŠãã»ãŒç¬æã«è¿ãããŸãã
ããã³ããšã³ãã§ããŒã«ãããŒãžã£ãŒãå®è£ ããããšã«ãããæ¥ç¶ã©ã€ããµã€ã¯ã«ãå€é©ãããŸããã³ã¹ãã®ãããåæåãã§ãŒãºã¯ããã¯ã°ã©ãŠã³ãã§äºåã«è¡ããããããæ°ãããã¢ãšã®å®éã®æ¥ç¶ç¢ºç«ã¯ãŠãŒã¶ãŒã®èŠç¹ããèŠãŠéåžžã«é«éã«ãªããŸãã
ã³ãã¯ã·ã§ã³ããŒã«ã®äž»ãªå©ç¹
- åçã«é å»¶ãåæž: æ¥ç¶ãäºåã«ãŠã©ãŒã ã¢ããããïŒã€ã³ã¹ã¿ã³ã¹åããå Žåã«ãã£ãŠã¯ICEã®ã£ã¶ãªã³ã°ãéå§ããïŒããšã«ãããæ°ãããã¢ãžã®æ¥ç¶æéãå€§å¹ ã«ççž®ãããŸããäž»ãªé å»¶ã¯ãå®å šãªããŽã·ãšãŒã·ã§ã³ããã*æ°ãã*ãã¢ãšã®æçµçãªSDP亀æãšDTLSãã³ãã·ã§ã€ã¯ã®ã¿ã«ç§»è¡ããããã¯åçã«é«éã§ãã
- ããäœããããã¹ã ãŒãºãªãªãœãŒã¹æ¶è²»: ããŒã«ãããŒãžã£ãŒã¯æ¥ç¶äœæã®ã¬ãŒããå¶åŸ¡ããCPUã¹ãã€ã¯ãå¹³æ»åã§ããŸãããªããžã§ã¯ããåå©çšããããšã§ãæ¥éãªå²ãåœãŠãšã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã«ãã£ãŠåŒãèµ·ããããã¡ã¢ãªãã£ãŒã³ãåæžãããããå®å®ããå¹ççãªã¢ããªã±ãŒã·ã§ã³ã«ã€ãªãããŸãã
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ïŒUXïŒã®å€§å¹ ãªåäž: ãŠãŒã¶ãŒã¯ãã»ãŒç¬æã®é話éå§ãéä¿¡ã»ãã·ã§ã³éã®ã·ãŒã ã¬ã¹ãªç§»è¡ããããŠå šäœçã«å¿çæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãäœéšã§ããŸãããã®ç¥èŠãããããã©ãŒãã³ã¹ã¯ãç«¶äºã®æ¿ãããªã¢ã«ã¿ã€ã åžå Žã«ãããŠéèŠãªå·®å¥åèŠå ãšãªããŸãã
- ã¢ããªã±ãŒã·ã§ã³ããžãã¯ã®ç°¡çŽ åãšäžå å: é©åã«èšèšãããããŒã«ãããŒãžã£ãŒã¯ãæ¥ç¶ã®äœæãåå©çšãããã³ã¡ã³ããã³ã¹ã®è€éããã«ãã»ã«åããŸããã¢ããªã±ãŒã·ã§ã³ã®æ®ãã®éšåã¯ãã¯ãªãŒã³ãªAPIãä»ããŠæ¥ç¶ãèŠæ±ããã³è§£æŸããã ãã§ãããããã¢ãžã¥ãŒã«åãããä¿å®ããããã³ãŒãã«ã€ãªãããŸãã
æ¥ç¶ããŒã«ãããŒãžã£ãŒã®èšèšïŒã¢ãŒããã¯ãã£ãšã³ã³ããŒãã³ã
å ç¢ãªWebRTCæ¥ç¶ããŒã«ãããŒãžã£ãŒã¯ãåãªããã¢æ¥ç¶ã®é å以äžã®ãã®ã§ããæ³šææ·±ãç¶æ 管çãæç¢ºãªååŸãšè§£æŸã®ãããã³ã«ããããŠã€ã³ããªãžã§ã³ããªã¡ã³ããã³ã¹ã«ãŒãã³ãå¿ èŠã§ãããã®ã¢ãŒããã¯ãã£ã®äžå¯æ¬ ãªã³ã³ããŒãã³ããåè§£ããŠã¿ãŸãããã
äž»èŠãªã¢ãŒããã¯ãã£ã³ã³ããŒãã³ã
- ããŒã«ã¹ãã¢: ããã¯ãRTCPeerConnectionãªããžã§ã¯ããä¿æããã³ã¢ããŒã¿æ§é ã§ããé åããã¥ãŒããŸãã¯ãããã§ããå¯èœæ§ããããŸããæ±ºå®çã«éèŠãªã®ã¯ã忥ç¶ã®ç¶æ ã远跡ããå¿ èŠãããããšã§ããäžè¬çãªç¶æ ã«ã¯ã'idle'ïŒäœ¿çšå¯èœïŒã'in-use'ïŒçŸåšãã¢ãšã¢ã¯ãã£ãïŒã'provisioning'ïŒäœæäžïŒãããã³'stale'ïŒã¯ãªãŒã³ã¢ãã察象ãšããŠããŒã¯æžã¿ïŒãå«ãŸããŸãã
- æ§æãã©ã¡ãŒã¿: æè»ãªããŒã«ãããŒãžã£ãŒã¯ãããŸããŸãªã¢ããªã±ãŒã·ã§ã³ã®ããŒãºã«åãããŠæ§æå¯èœã§ããã¹ãã§ããäž»èŠãªãã©ã¡ãŒã¿ã¯ä»¥äžã®éãã§ã:
- minSize: åžžã«'ãŠã©ãŒã 'ã«ä¿ã€ã¢ã€ãã«æ¥ç¶ã®æå°æ°ãããŒã«ã¯ãã®æå°æ°ãæºããããã«æ¥ç¶ãç©æ¥µçã«äœæããŸãã
- maxSize: ããŒã«ã管çã§ããæ¥ç¶ã®çµ¶å¯Ÿæå€§æ°ãããã«ãããæŽèµ°ãããªãœãŒã¹æ¶è²»ãé²ããŸãã
- idleTimeout: æ¥ç¶ã'idle'ç¶æ ã«çãŸãããšãã§ããæå€§æéïŒããªç§åäœïŒããã®æéãè¶ ãããšããªãœãŒã¹ãè§£æŸããããã«éããããåé€ãããŸãã
- creationTimeout: ICEã®ã£ã¶ãªã³ã°ã忢ããå Žåã«å¯ŸåŠããããã®ãåææ¥ç¶èšå®ã®ã¿ã€ã ã¢ãŠãã
- ååŸããžãã¯ïŒäŸïŒacquireConnection()ïŒ: ããã¯ãã¢ããªã±ãŒã·ã§ã³ãæ¥ç¶ãååŸããããã«åŒã³åºãå
¬éã¡ãœããã§ãããã®ããžãã¯ã¯æ¬¡ã®ããã«ãªããŸã:
- ããŒã«å ã§'idle'ç¶æ ã®æ¥ç¶ãæ€çŽ¢ããŸãã
- èŠã€ãã£ãå Žåãããã'in-use'ãšããŠããŒã¯ããè¿ããŸãã
- èŠã€ãããªãã£ãå Žåãæ¥ç¶ã®ç·æ°ãmaxSizeæªæºã§ãããã確èªããŸãã
- ããã§ããå Žåãæ°ããæ¥ç¶ãäœæãããããããŒã«ã«è¿œå ãã'in-use'ãšããŠããŒã¯ããŠè¿ããŸãã
- ããŒã«ãmaxSizeã«éããŠããå ŽåãèŠæ±ã¯ãæãŸããæŠç¥ã«å¿ããŠããã¥ãŒã«å ¥ãããããæåŠããããã®ããããã§ãã
- è§£æŸããžãã¯ïŒäŸïŒreleaseConnection()ïŒ: ã¢ããªã±ãŒã·ã§ã³ãæ¥ç¶ã®äœ¿çšãçµãããããããããŒã«ã«æ»ãå¿
èŠããããŸããããã¯ãããŒãžã£ãŒã®æãéèŠã§åŸ®åŠãªéšåã§ããããã«ã¯ä»¥äžãå«ãŸããŸã:
- è§£æŸãããRTCPeerConnectionãªããžã§ã¯ããåãåããŸãã
- ããã*ç°ãªã*ãã¢ã§åå©çšå¯èœã«ããããã®'ãªã»ãã'æäœãå®è¡ããŸãããªã»ããæŠç¥ã«ã€ããŠã¯åŸã§è©³ãã説æããŸãã
- ãã®ç¶æ ã'idle'ã«æ»ããŸãã
- idleTimeoutã¡ã«ããºã ã®ããã«ããã®æçµäœ¿çšã¿ã€ã ã¹ã¿ã³ããæŽæ°ããŸãã
- ã¡ã³ããã³ã¹ãšãã«ã¹ãã§ãã¯: éåžžãsetIntervalã䜿çšããŠãããŒã«ã宿çã«ã¹ãã£ã³ããããã¯ã°ã©ãŠã³ãããã»ã¹ã§ã以äžã®ããšãè¡ããŸã:
- ã¢ã€ãã«æ¥ç¶ã®åé€: idleTimeoutãè¶ éãã'idle'æ¥ç¶ãéããåé€ããŸãã
- æå°ãµã€ãºã®ç¶æ: å©çšå¯èœãªïŒã¢ã€ãã«+ããããžã§ãã³ã°äžïŒæ¥ç¶ã®æ°ãå°ãªããšãminSizeã§ããããšãä¿èšŒããŸãã
- ãã«ã¹ã¢ãã¿ãªã³ã°: æ¥ç¶ç¶æ ã€ãã³ãïŒäŸïŒ'iceconnectionstatechange'ïŒããªãã¹ã³ãã倱æããæ¥ç¶ãåæãããæ¥ç¶ãããŒã«ããèªåçã«åé€ããŸãã
ããŒã«ãããŒãžã£ãŒã®å®è£ ïŒå®è·µçã§æŠå¿µçãªãŠã©ãŒã¯ã¹ã«ãŒ
ç§ãã¡ã®èšèšãæŠå¿µçãªJavaScriptã¯ã©ã¹æ§é ã«å€æããŠã¿ãŸãããããã®ã³ãŒãã¯ã³ã¢ããžãã¯ã匷調ããããã®äŸç€ºã§ããããããã¯ã·ã§ã³å¯Ÿå¿ã®ã©ã€ãã©ãªã§ã¯ãããŸããã
// WebRTCã³ãã¯ã·ã§ã³ããŒã«ãããŒãžã£ãŒã®æŠå¿µçãªJavaScriptã¯ã©ã¹
class WebRTCPoolManager { constructor(config) { this.config = { minSize: 2, maxSize: 10, idleTimeout: 30000, // 30ç§ iceServers: [], // æäŸå¿ é ...config }; this.pool = []; // { pc, state, lastUsed } ãªããžã§ã¯ããæ ŒçŽããé å this._initializePool(); this.maintenanceInterval = setInterval(() => this._runMaintenance(), 5000); } _initializePool() { /* ... */ } _createAndProvisionPeerConnection() { /* ... */ } _resetPeerConnectionForReuse(pc) { /* ... */ } _runMaintenance() { /* ... */ } async acquire() { /* ... */ } release(pc) { /* ... */ } destroy() { clearInterval(this.maintenanceInterval); /* ... ãã¹ãŠã®pcãéãã */ } }
ã¹ããã1ïŒããŒã«ã®åæåãšãŠã©ãŒã ã¢ãã
ã³ã³ã¹ãã©ã¯ã¿ã¯æ§æãèšå®ããåæã®ããŒã«æå ¥ãéå§ããŸãã_initializePool()ã¡ãœããã¯ãããŒã«ãæåããminSizeã®æ¥ç¶ã§æºããããããšãä¿èšŒããŸãã
_initializePool() { for (let i = 0; i < this.config.minSize; i++) { this._createAndProvisionPeerConnection(); } } async _createAndProvisionPeerConnection() { const pc = new RTCPeerConnection({ iceServers: this.config.iceServers }); const poolEntry = { pc, state: 'provisioning', lastUsed: Date.now() }; this.pool.push(poolEntry); // ãããŒãªãã¡ãŒãäœæããŠãICEã®ã£ã¶ãªã³ã°ãäºåã«éå§ããŸãã // ããã¯äž»èŠãªæé©åã§ãã const offer = await pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true }); await pc.setLocalDescription(offer); // ICEã®ã£ã¶ãªã³ã°ãå®äºããã®ãåŸ ã¡ãŸãã pc.onicegatheringstatechange = () => { if (pc.iceGatheringState === 'complete') { poolEntry.state = 'idle'; console.log("æ°ãããã¢æ¥ç¶ããŠã©ãŒã ã¢ãããããããŒã«å ã§æºåå®äºã§ãã"); } }; // 倱æãåŠçããŸã pc.oniceconnectionstatechange = () => { if (pc.iceConnectionState === 'failed') { this._removeConnection(pc); } }; return poolEntry; }
ãã®ããŠã©ãŒã ã¢ãããããã»ã¹ããããäž»èŠãªé å»¶åæžã®å©ç¹ããããããŸãããªãã¡ãŒãäœæããããŒã«ã«èšè¿°ãå³åº§ã«èšå®ããããšã§ããŠãŒã¶ãŒãæ¥ç¶ãå¿ èŠãšãããã£ãšåã«ããã©ãŠã¶ã«ã³ã¹ãã®ãããICEã®ã£ã¶ãªã³ã°ããã»ã¹ãããã¯ã°ã©ãŠã³ãã§éå§ãããŸãã
ã¹ããã2ïŒ`acquire()`ã¡ãœãã
ãã®ã¡ãœããã¯ãå©çšå¯èœãªæ¥ç¶ãèŠã€ããããæ°ããæ¥ç¶ãäœæããããŒã«ã®ãµã€ãºå¶çŽã管çããŸãã
async acquire() { // æåã®ã¢ã€ãã«æ¥ç¶ãèŠã€ãã let idleEntry = this.pool.find(entry => entry.state === 'idle'); if (idleEntry) { idleEntry.state = 'in-use'; idleEntry.lastUsed = Date.now(); return idleEntry.pc; } // ã¢ã€ãã«æ¥ç¶ããªãå Žåãæå€§ãµã€ãºã«éããŠããªããã°æ°ããæ¥ç¶ãäœæãã if (this.pool.length < this.config.maxSize) { console.log("ããŒã«ã空ã§ããæ°ãããªã³ããã³ãæ¥ç¶ãäœæããŠããŸãã"); const newEntry = await this._createAndProvisionPeerConnection(); newEntry.state = 'in-use'; // çŽã¡ã«äœ¿çšäžã«ããŒã¯ return newEntry.pc; } // ããŒã«ãæå€§å®¹éã«éããŠããããã¹ãŠã®æ¥ç¶ã䜿çšäž throw new Error("WebRTCæ¥ç¶ããŒã«ãæ¯æžããŸããã"); }
ã¹ããã3ïŒ`release()`ã¡ãœãããšæ¥ç¶ãªã»ããã®åŠæ
ããã¯æè¡çã«æãé£ããéšåã§ããRTCPeerConnectionã¯ã¹ããŒããã«ã§ãããã¢Aãšã®ã»ãã·ã§ã³ãçµäºããåŸããã®ç¶æ ããªã»ããããã«åã«ãã¢Bã«æ¥ç¶ããããã«ããã䜿çšããããšã¯ã§ããŸãããããã广çã«è¡ãã«ã¯ã©ãããã°ããã§ããããïŒ
åã«pc.close()ãåŒã³åºããŠæ°ãããã®ãäœæããããšã¯ãããŒã«ã®ç®çãæã¡æ¶ããŸãã代ããã«ãããœãããªã»ããããå¿ èŠã§ããæãå ç¢ãªçŸä»£çãªã¢ãããŒãã¯ããã©ã³ã·ãŒããŒã®ç®¡çã䌎ããŸãã
_resetPeerConnectionForReuse(pc) { return new Promise(async (resolve, reject) => { // 1. æ¢åã®ãã¹ãŠã®ãã©ã³ã·ãŒããŒã忢ããŠåé€ãã pc.getTransceivers().forEach(transceiver => { if (transceiver.sender && transceiver.sender.track) { transceiver.sender.track.stop(); } // ãã©ã³ã·ãŒããŒã忢ããæ¹ãããæç¢ºãªã¢ã¯ã·ã§ã³ã§ã if (transceiver.stop) { transceiver.stop(); } }); // 泚ïŒãã©ãŠã¶ã®ããŒãžã§ã³ã«ãã£ãŠã¯ããã©ãã¯ãæåã§åé€ããå¿ èŠãããå ŽåããããŸãã // pc.getSenders().forEach(sender => pc.removeTrack(sender)); // 2. 次ã®ãã¢ã®ããã®æ°ããåè£ã確ä¿ããããã«ãå¿ èŠã«å¿ããŠICEãåèµ·åããã // ããã¯ãæ¥ç¶ã䜿çšäžã«ãããã¯ãŒã¯å€æŽãåŠçããããã«äžå¯æ¬ ã§ãã if (pc.restartIce) { pc.restartIce(); } // 3. æ¥ç¶ã*次ã®*ããŽã·ãšãŒã·ã§ã³ã®ããã®æ¢ç¥ã®ç¶æ ã«æ»ãããã«ãæ°ãããªãã¡ãŒãäœæãã // ããã¯æ¬è³ªçã«ãæ¥ç¶ãããŠã©ãŒã ã¢ããããããç¶æ ã«æ»ããŸãã try { const offer = await pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true }); await pc.setLocalDescription(offer); resolve(); } catch (error) { reject(error); } }); } async release(pc) { const poolEntry = this.pool.find(entry => entry.pc === pc); if (!poolEntry) { console.warn("ãã®ããŒã«ã«ãã£ãŠç®¡çãããŠããªãæ¥ç¶ãè§£æŸããããšããŸããã"); pc.close(); // å®å šã®ããéãã return; } try { await this._resetPeerConnectionForReuse(pc); poolEntry.state = 'idle'; poolEntry.lastUsed = Date.now(); console.log("æ¥ç¶ã¯æ£åžžã«ãªã»ãããããããŒã«ã«æ»ãããŸããã"); } catch (error) { console.error("ãã¢æ¥ç¶ã®ãªã»ããã«å€±æããŸãããããŒã«ããåé€ããŸãã", error); this._removeConnection(pc); // ãªã»ããã倱æããå Žåãæ¥ç¶ã¯äœ¿çšäžèœã§ããå¯èœæ§ãé«ãã§ãã } }
ã¹ããã4ïŒã¡ã³ããã³ã¹ãšåªå®
æåŸã®èŠçŽ ã¯ãããŒã«ãå¥å šãã€å¹ççã«ä¿ã€ããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ã§ãã
_runMaintenance() { const now = Date.now(); const idleConnectionsToPrune = []; this.pool.forEach(entry => { // é·æéã¢ã€ãã«ç¶æ ã ã£ãæ¥ç¶ãåªå®ãã if (entry.state === 'idle' && (now - entry.lastUsed > this.config.idleTimeout)) { idleConnectionsToPrune.push(entry.pc); } }); if (idleConnectionsToPrune.length > 0) { console.log(`${idleConnectionsToPrune.length}åã®ã¢ã€ãã«æ¥ç¶ãåªå®ããŠããŸãã`); idleConnectionsToPrune.forEach(pc => this._removeConnection(pc)); } // æå°ãµã€ãºãæºããããã«ããŒã«ãè£å ãã const currentHealthySize = this.pool.filter(e => e.state === 'idle' || e.state === 'in-use').length; const needed = this.config.minSize - currentHealthySize; if (needed > 0) { console.log(`ããŒã«ã${needed}åã®æ°ããæ¥ç¶ã§è£å ããŠããŸãã`); for (let i = 0; i < needed; i++) { this._createAndProvisionPeerConnection(); } } } _removeConnection(pc) { const index = this.pool.findIndex(entry => entry.pc === pc); if (index !== -1) { this.pool.splice(index, 1); pc.close(); } }
é«åºŠãªæŠå¿µãšã°ããŒãã«ãªèæ ®äºé
åºæ¬çãªããŒã«ãããŒãžã£ãŒã¯çŽ æŽãããåºçºç¹ã§ãããå®éã®ã¢ããªã±ãŒã·ã§ã³ã«ã¯ããè€éãªãã¥ã¢ã³ã¹ãå¿ èŠã§ãã
STUN/TURNèšå®ãšåçèªèšŒæ å ±ã®åŠç
TURNãµãŒããŒã®èªèšŒæ å ±ã¯ãã»ãã¥ãªãã£äžã®çç±ããçåœã§ããããšããããããŸãïŒäŸïŒ30ååŸã«æéåãã«ãªãïŒãããŒã«å ã®ã¢ã€ãã«æ¥ç¶ã¯ãèªèšŒæ å ±ãæéåãã«ãªã£ãŠããå¯èœæ§ããããŸããããŒã«ãããŒãžã£ãŒã¯ãããåŠçããå¿ èŠããããŸããRTCPeerConnectionã®setConfiguration()ã¡ãœãããéµãšãªããŸããæ¥ç¶ãååŸããåã«ãã¢ããªã±ãŒã·ã§ã³ããžãã¯ã§èªèšŒæ å ±ã®æå¹æéã確èªããå¿ èŠã«å¿ããŠpc.setConfiguration({ iceServers: newIceServers })ãåŒã³åºããŠãæ°ããæ¥ç¶ãªããžã§ã¯ããäœæããããšãªãèªèšŒæ å ±ãæŽæ°ã§ããŸãã
ç°ãªãã¢ãŒããã¯ãã£ïŒSFU vs. ã¡ãã·ã¥ïŒãžã®ããŒã«ã®é©å¿
- SFU (Selective Forwarding Unit): ãã®äžè¬çãªã¢ãŒããã¯ãã£ã§ã¯ãã¯ã©ã€ã¢ã³ãã¯éåžžãäžå€®ã®ã¡ãã£ã¢ãµãŒããŒã«å¯ŸããŠ1ã€ãŸãã¯2ã€ã®äž»èŠãªãã¢æ¥ç¶ããæã¡ãŸããïŒã¡ãã£ã¢å ¬éçšã1ã€ã賌èªçšã1ã€ïŒãããã§ã¯ãå°èŠæš¡ãªããŒã«ïŒäŸïŒminSize: 1, maxSize: 2ïŒã§ãè¿ éãªåæ¥ç¶ãé«éãªåææ¥ç¶ã確ä¿ããã®ã«ååã§ãã
- ã¡ãã·ã¥ãããã¯ãŒã¯: åã¯ã©ã€ã¢ã³ããä»ã®è€æ°ã®ã¯ã©ã€ã¢ã³ãã«æ¥ç¶ãããã¢ããŒãã¢ã¡ãã·ã¥ã§ã¯ãããŒã«ãã¯ããã«éèŠã«ãªããŸããè€æ°ã®åææ¥ç¶ã«å¯Ÿå¿ããããã«maxSizeã倧ããããå¿ èŠãããããã¢ãã¡ãã·ã¥ã«åå ãããé¢ãããããã«ã€ããŠãacquire/releaseãµã€ã¯ã«ã¯ã¯ããã«é »ç¹ã«ãªããŸãã
ãããã¯ãŒã¯å€æŽãšãå€ããæ¥ç¶ã®åŠç
ãŠãŒã¶ãŒã®ãããã¯ãŒã¯ã¯ãã€ã§ã倿Žãããå¯èœæ§ããããŸãïŒäŸïŒWi-Fiããã¢ãã€ã«ãããã¯ãŒã¯ãžã®åãæ¿ãïŒãããŒã«å ã®ã¢ã€ãã«æ¥ç¶ã¯ãçŸåšç¡å¹ã«ãªã£ãŠããICEåè£ãåéããŠããå¯èœæ§ããããŸããããã§restartIce()ãéåžžã«è²Žéã«ãªããŸããå ç¢ãªæŠç¥ãšããŠã¯ãacquire()ããã»ã¹ã®äžéšãšããŠæ¥ç¶ã«å¯ŸããŠrestartIce()ãåŒã³åºãããšãèããããŸããããã«ãããæ°ãããã¢ãšã®ããŽã·ãšãŒã·ã§ã³ã«äœ¿çšãããåã«ãæ¥ç¶ãææ°ã®ãããã¯ãŒã¯ãã¹æ å ±ãæã€ããšãä¿èšŒãããããããªé å»¶ãå ãããã®ã®ãæ¥ç¶ã®ä¿¡é Œæ§ãå€§å¹ ã«åäžããŸãã
ããã©ãŒãã³ã¹ãã³ãããŒã¯ïŒå ·äœçãªåœ±é¿
ã³ãã¯ã·ã§ã³ããŒã«ã®å©ç¹ã¯çè«çãªãã®ã ãã§ã¯ãããŸãããæ°ããP2Pãããªé話ã確ç«ããããã®ä»£è¡šçãªæ°åãèŠãŠã¿ãŸãããã
ã·ããªãªïŒã³ãã¯ã·ã§ã³ããŒã«ãªã
- T0: ãŠãŒã¶ãŒããé話ããã¯ãªãã¯ã
- T0 + 10ms: new RTCPeerConnection()ãåŒã³åºãããã
- T0 + 200-800ms: ãªãã¡ãŒãäœæãããããŒã«ã«èšè¿°ãèšå®ãããICEã®ã£ã¶ãªã³ã°ãéå§ãããã·ã°ããªã³ã°ãä»ããŠãªãã¡ãŒãéä¿¡ãããã
- T0 + 400-1500ms: ã¢ã³ãµãŒãåä¿¡ããããªã¢ãŒãèšè¿°ãèšå®ãããICEåè£ã亀æããã³ãã§ãã¯ãããã
- T0 + 500-2000ms: æ¥ç¶ã確ç«ãããã æåã®ã¡ãã£ã¢ãã¬ãŒã ãŸã§ã®æé: çŽ0.5ã2ç§ã
ã·ããªãªïŒãŠã©ãŒã ã¢ãããããã³ãã¯ã·ã§ã³ããŒã«ã䜿çšããå Žå
- ããã¯ã°ã©ãŠã³ã: ããŒã«ãããŒãžã£ãŒã¯ãã§ã«æ¥ç¶ãäœæããåæICEã®ã£ã¶ãªã³ã°ãå®äºããŠããŸãã
- T0: ãŠãŒã¶ãŒããé話ããã¯ãªãã¯ã
- T0 + 5ms: pool.acquire()ãäºåãŠã©ãŒã ã¢ãããããæ¥ç¶ãè¿ããŸãã
- T0 + 10ms: æ°ãããªãã¡ãŒãäœæããïŒICEãåŸ ããªãããé«éïŒãã·ã°ããªã³ã°ãä»ããŠéä¿¡ãããŸãã
- T0 + 200-500ms: ã¢ã³ãµãŒãåä¿¡ãããèšå®ãããŸããæçµçãªDTLSãã³ãã·ã§ã€ã¯ã¯ããã§ã«æ€èšŒæžã¿ã®ICEãã¹ãä»ããŠå®äºããŸãã
- T0 + 250-600ms: æ¥ç¶ã確ç«ãããã æåã®ã¡ãã£ã¢ãã¬ãŒã ãŸã§ã®æé: çŽ0.25ã0.6ç§ã
çµæã¯æããã§ããã³ãã¯ã·ã§ã³ããŒã«ã¯ãç°¡åã«æ¥ç¶é å»¶ã50ã75%以äžåæžã§ããŸããããã«ãæ¥ç¶èšå®ã®CPUè² è·ãããã¯ã°ã©ãŠã³ãã§æéçã«åæ£ãããããšã§ããŠãŒã¶ãŒãã¢ã¯ã·ã§ã³ãéå§ããç¬éã«çºçããäžå¿«ãªããã©ãŒãã³ã¹ã¹ãã€ã¯ãæé€ããã¯ããã«ã¹ã ãŒãºã§ãããã§ãã·ã§ãã«ãªæèŠã®ã¢ããªã±ãŒã·ã§ã³ã«ã€ãªãããŸãã
çµè«ïŒãããã§ãã·ã§ãã«WebRTCã®ããã®å¿ é ã³ã³ããŒãã³ã
ãªã¢ã«ã¿ã€ã ãŠã§ãã¢ããªã±ãŒã·ã§ã³ãè€éããå¢ããããã©ãŒãã³ã¹ã«å¯ŸãããŠãŒã¶ãŒã®æåŸ ãé«ãŸãç¶ããã«ã€ããŠãããã³ããšã³ãã®æé©åãæéèŠèª²é¡ãšãªããŸããRTCPeerConnectionãªããžã§ã¯ãã¯åŒ·åã§ããäžæ¹ã§ããã®äœæãšããŽã·ãšãŒã·ã§ã³ã«ã¯ããªãã®ããã©ãŒãã³ã¹ã³ã¹ããããããŸããåäžã®é·æéåç¶ãããã¢æ¥ç¶ä»¥äžã®ãã®ãå¿ èŠãšããã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠããã®ã³ã¹ãã管çããããšã¯éžæè¢ã§ã¯ãªããå¿ é ã§ãã
WebRTCããã³ããšã³ãæ¥ç¶ããŒã«ãããŒãžã£ãŒã¯ãé å»¶ãšãªãœãŒã¹æ¶è²»ãšããäž»èŠãªããã«ããã¯ã«çŽæ¥å¯ŸåŠããŸãããã¢æ¥ç¶ãç©æ¥µçã«äœæããŠã©ãŒã ã¢ãããå¹ççã«åå©çšããããšã§ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãé ãäºæž¬äžå¯èœãªãã®ãããç¬æã§ä¿¡é Œæ§ã®é«ããã®ãžãšå€é©ããŸããããŒã«ãããŒãžã£ãŒãå®è£ ããããšã¯ã¢ãŒããã¯ãã£ã®è€éããäžå±€é«ããŸãããããã©ãŒãã³ã¹ãã¹ã±ãŒã©ããªãã£ãã³ãŒãã®ä¿å®æ§ã«ãããèŠè¿ãã¯èšãç¥ããŸããã
ãªã¢ã«ã¿ã€ã éä¿¡ã®ã°ããŒãã«ã§ç«¶äºã®æ¿ããç°å¢ã§æŽ»åããéçºè ãã¢ãŒããã¯ãã«ãšã£ãŠããã®ãã¿ãŒã³ãæ¡çšããããšã¯ããã®é床ãšå¿çæ§ã§ãŠãŒã¶ãŒãåã°ããçã«ã¯ãŒã«ãã¯ã©ã¹ã®ãããã§ãã·ã§ãã«ã°ã¬ãŒãã®ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®æŠç¥çãªäžæ©ã§ãã